/**
 * @file   Schedules.java
 * @author Enrique Madrid <e.madrid@lpcsite.com>
 * @date   Tue Oct  2 13:11:54 2007
 * 
 * @brief  
 * 
 * 
 */

package com.myt.matp.core;

import com.myt.matp.MATlet;
import com.myt.matp.utils.Queue;
import com.myt.matp.utils.Util;

import java.util.*;

/**
 * 
 * 
 */
public final class Scheduler extends Ufo {

    // Message queue size
    private static final int QUEUE_INIT_SIZE = 16;

    public static final int MSG_WAIT = MSG_USER + 1;

    private Vector m_Alarms = new Vector(QUEUE_INIT_SIZE);
    //private Group m_Actives = new Queue(QUEUE_INIT_SIZE);
    private Queue m_Recycle = new Queue(QUEUE_INIT_SIZE);
    
    public Scheduler(MATlet m) {
	super(m);
    }

    protected void run(final Msg msg) {

        //#ifdef DEBUG_SCHEDULER
        //# System.out.println(getClass().getName() + ".run(Msg) {");
        //#endif

	switch (msg.getId()) {
	case MSG_TOUT:
	    Enumeration e = m_Alarms.elements();
	    Msg alarm;
	    while (e.hasMoreElements()) {
		alarm = (Msg)e.nextElement();
		alarm.setWParam(alarm.getWParam() + 1);
		if (alarm.getWParam() == alarm.getDWParam() / getWait()) {
		    alarm.setWParam(0);
		    m_MATlet.postEvent(Event.SC_ALARM, 0, 0, alarm.getObject());
		}
	    }
	    break;
	case MSG_WAIT:
	    break;
	}

        //#ifdef DEBUG_SCHEDULER
        //# System.out.println("}");
        //#endif
    }

    private Msg newAlarm(int id, long period, EventListener e) {
	Msg a = (Msg)m_Recycle.get();
	if (a == null) {
	    a = new Msg(id);
	}
	a.set(null);
	a.setId(id);
	a.setWParam(0);
	a.setDWParam(period);
	a.setObject(e);
	return a;
    }

    private void computeTestingPeriod() {
	Enumeration e;
        Msg alarm;
	long wait;
        
        // Si no hay alarmas el MCD es cero
        wait = 0;

	if (m_Alarms.size() > 0) {
	    e = m_Alarms.elements();
	    // Inicializar el MCD
	    alarm = (Msg)e.nextElement();
	    wait = alarm.getDWParam();
	    // Calcular el MCD con todas las alarmas
	    while (e.hasMoreElements()) {
		alarm = (Msg)e.nextElement();
		wait = (int)Util.computeMCD((int)wait, (int)alarm.getDWParam());
	    }
	}

	setWait(wait);
    }

    public void initAlarm(int id, long period, EventListener e) {
	if ((period > 0) && (e != null)) {
	    // Insert new alarm
	    Msg alarm = newAlarm(id, period, e);

	    m_Alarms.addElement(alarm);

	    // Compute sleeping time
	    computeTestingPeriod();
	}
    }

    public void killAlarm(int id) {
	Msg alarm = null;
	Enumeration e = m_Alarms.elements();
	while (e.hasMoreElements()) {
	    alarm = (Msg)e.nextElement();
	    if (alarm.getId() == id) {
		break;
	    }
	    else {
		alarm = null;
	    }
	}

	if (alarm != null) {
	    m_Alarms.removeElement(alarm);
	    m_Recycle.put(alarm);
	    computeTestingPeriod();
	}
    }
}
